﻿using Microsoft.Vbe.Interop;
using System;
using System.Collections.Generic;

using System.Diagnostics;

using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace VBACodeingTool
{
    public static class VBEHelper
    {
        #region VBE

        public static VBComponent GetCurrentComponent()
        {
            return ProgramInstanceManager.VBE.SelectedVBComponent;
        }

        public static VBProject GetCurrentVBProject()
        {
            return ProgramInstanceManager.VBE.ActiveVBProject;
        }

        public static CodePane GetCurrentCodePane()
        {
            return ProgramInstanceManager.VBE.CodePanes.Current;
        }

        public static CodeModule GetCurrentCodeModule()
        {
            return GetCurrentCodePane().CodeModule;
        }

        public static void GetCurrentLineRowAndColumn(out int startRow, out int startColumn, out int endRow, out int endColumn)
        {
            GetCurrentCodePane().GetSelection(out startRow, out startColumn, out endRow, out endColumn);
        }

        public static void SetCurrentLineRowAndColumn(int startRow, int startColumn, int endRow, int endColumn)
        {
            GetCurrentCodePane().SetSelection(startRow, startColumn, endRow, endColumn);
        }

        public static string GetCurrentLineString(int startLine)
        {
            return GetMultiLineString(startLine, 1);
        }

        public static string GetMultiLineString(int startLine, int lineNumber)
        {
            return GetCurrentCodeModule().Lines[startLine, lineNumber];
        }

        public static string GetSelectionCode()
        {
            VBEHelper.GetCurrentLineRowAndColumn(out int a, out int b, out int c, out int d);
            string content;
            if (a == c)
            {
                content = VBEHelper.GetCurrentLineString(c);
            }
            else
            {
                content = VBEHelper.GetMultiLineString(a, c - a + 1);
            }
            return content;
        }

        public static string GetCurrentSubContent()
        {
            int line = VBEHelper.GetCodeAndPosition().Position.startRow;
            vbext_ProcKind vbext_ProcKind = vbext_ProcKind.vbext_pk_Proc;
            CodeModule codeModule = VBEHelper.GetCurrentCodeModule();
            string currentSub = codeModule.ProcOfLine[line, out vbext_ProcKind];
            if (vbext_ProcKind.vbext_pk_Proc == vbext_ProcKind&& currentSub!=null)
            {
                int startLine = codeModule.ProcBodyLine[currentSub, vbext_ProcKind];
                int endLine = codeModule.ProcCountLines[currentSub, vbext_ProcKind];
                return codeModule.Lines[startLine, endLine];
            }
            return null;
        }

        public static CodeAndPosition GetCodeAndPosition()
        {
            VBEHelper.GetCurrentLineRowAndColumn(out int a, out int b, out int c, out int d);
            string content;
            if (a == c)
            {
                content = VBEHelper.GetCurrentLineString(c);
            }
            else
            {
                content = VBEHelper.GetMultiLineString(a, c - a + 1);
            }
            Position position = new Position
            {
                startRow = a,
                startColumn = b,
                endColumn = d,
                endRow = c
            };
            CodeAndPosition codeAndPosition = new CodeAndPosition
            {
                Content = content,
                Position = position,
                IsMultiLines = a != c
            };
            return codeAndPosition;
        }

        public struct CodeAndPosition
        {
            public string Content { get; set; }
            public Position Position { get; set; }
            public bool IsMultiLines { get; set; }
        }

        public struct Position
        {
            public int startRow;
            public int startColumn;
            public int endRow;
            public int endColumn;
        }

        public struct ShortCutAndPosition
        {
            public CodeAndPosition selfCodeAndPosition;
            public string shortCut;
        }

        public static ShortCutAndPosition GetShortCut()
        {
            CodeAndPosition codeAndPosition = VBEHelper.GetCodeAndPosition();
            if (!codeAndPosition.IsMultiLines && codeAndPosition.Content != "")
            {
                if ((codeAndPosition.Position.startColumn==codeAndPosition.Position.endColumn))
                {
                    int index = codeAndPosition.Position.startColumn - RegexManager.ChineseCountRegex.Matches(codeAndPosition.Content).Count;
                    if ((index - 1) == codeAndPosition.Content.Length)
                    {
                        return new ShortCutAndPosition()
                        {
                            selfCodeAndPosition = codeAndPosition,
                            shortCut = codeAndPosition.Content.Split(' ').Last()
                        };
                    }
                    if ((index - 1) < codeAndPosition.Content.Length)
                    {
                        string beforeCursor = codeAndPosition.Content.Remove(index - 1);
                        return new ShortCutAndPosition()
                        {
                            selfCodeAndPosition = codeAndPosition,
                            shortCut = beforeCursor.Split(' ').Last()
                        };
                    }
                }
            }
            return new ShortCutAndPosition()
            {
                selfCodeAndPosition = codeAndPosition,
                shortCut = null
            };
        }

        public static IntPtr GetCodeWindowHwnd()
        {
            string name = VBEHelper.GetCurrentCodePane().Window.Caption;
            IntPtr hwndParent = (IntPtr)ProgramInstanceManager.VBE.MainWindow.HWnd;
            IntPtr hwndSon = User32.FindWindowEx(hwndParent, 0, "MDIClient", null);
            return User32.FindWindowEx(hwndSon, 0, "VbaWindow", name);
        }

        public static bool InsertCurrentLineStr(string content, string shortCut)
        {
            CodeAndPosition codeAndPosition;
            codeAndPosition = GetCodeAndPosition();
            if (codeAndPosition.IsMultiLines)
            {
                return false;
            }
            StringBuilder origin = new StringBuilder(codeAndPosition.Content);
            int column = codeAndPosition.Position.startColumn - 1;
            //下面减去中文的个数是因为中文在 codeWindow中是占两个位置的
            column -= RegexManager.ChineseCountRegex.Matches(origin.ToString()).Count;
            if (column >= shortCut.Length)
            {
                origin.Remove(column - shortCut.Length, shortCut.Length);
                origin = origin.Insert(column - shortCut.Length, content);
            }
            else
            {
                origin = origin.Insert(column, content);
            }
            GetCurrentCodeModule().ReplaceLine(codeAndPosition.Position.startRow, origin.ToString());
            int selectColumn = codeAndPosition.Position.startColumn + content.Length + RegexManager.ChineseCountRegex.Matches(content).Count;
            SetCurrentLineRowAndColumn(codeAndPosition.Position.startRow, selectColumn, codeAndPosition.Position.startRow, selectColumn);
            return true;
        }

        #endregion VBE
    }
}